﻿using System;
using System.Text.RegularExpressions;

namespace Foundation
{
    /// <summary>
    /// Extension methods for strings.
    /// </summary>
    public static class StringExtensions
    {
        /// <summary>
        /// Searches the by regex.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="pattern">The pattern.</param>
        /// <param name="startIndex">The start index.</param>
        /// <param name="directSearch">if set to <c>true</c> [direct search].</param>
        /// <param name="matchCase">if set to <c>true</c> [match case].</param>
        /// <param name="matchWholeWord">if set to <c>true</c> [match whole word].</param>
        /// <returns></returns>
        public static Match SearchByRegex(this string text, string pattern, int startIndex = 0, bool directSearch = true, bool matchCase = true, bool matchWholeWord = false)
        {
            var regexOptions = directSearch ? RegexOptions.None : RegexOptions.RightToLeft;
            var regex = new Regex(pattern, regexOptions);

            do
            {
                var math = regex.Match(text, startIndex);
                var result = math.ToString();

                if (matchWholeWord && !string.IsNullOrEmpty(result) && !text.IsWholeWord(result, math.Index))
                {
                    if (directSearch)
                    {
                        startIndex++;
                    }
                    else
                    {
                        startIndex--;
                    }

                    continue;
                }

                return math;
            }
            while (true);
        }

        /// <summary>
        /// Searches the by pattern.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="pattern">The pattern.</param>
        /// <param name="startIndex">The start index.</param>
        /// <param name="directSearch">if set to <c>true</c> [direct search].</param>
        /// <param name="matchCase">if set to <c>true</c> [match case].</param>
        /// <param name="matchWholeWord">if set to <c>true</c> [match whole word].</param>
        /// <returns></returns>
        public static int SearchByPattern(this string text, string pattern, int startIndex, bool directSearch = true, bool matchCase = true, bool matchWholeWord = false)
        {
            var stringComparison = matchCase ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;

            do
            {
                startIndex = directSearch
                                 ? text.DirectSearchByPattern(pattern, startIndex, stringComparison)
                                 : text.ReverseSearchByPattern(pattern, startIndex, stringComparison);

                if (matchWholeWord && 0 <= startIndex && startIndex < text.Length && !text.IsWholeWord(pattern, startIndex))
                {
                    if (directSearch)
                    {
                        startIndex += pattern.Length;
                    }

                    continue;
                }

                return startIndex;
            }
            while (true);
        }

        /// <summary>
        /// Directs the search by pattern.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="pattern">The pattern.</param>
        /// <param name="startIndex">The start index.</param>
        /// <param name="stringComparison">The string comparison.</param>
        /// <returns></returns>
        public static int DirectSearchByPattern(this string text, string pattern, int startIndex, StringComparison stringComparison)
        {
            return text.IndexOf(pattern, startIndex, stringComparison);
        }

        /// <summary>
        /// Reverses the search by pattern.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="pattern">The pattern.</param>
        /// <param name="startIndex">The start index.</param>
        /// <param name="stringComparison">The string comparison.</param>
        /// <returns></returns>
        public static int ReverseSearchByPattern(this string text, string pattern, int startIndex, StringComparison stringComparison)
        {
            startIndex--;
            for (var count = 1; startIndex >= 0; startIndex--, count++)
            {
                var index = text.IndexOf(pattern, startIndex, count, stringComparison);
                if (index >= 0)
                {
                    return index;
                }
            }

            return -1;
        }

        /// <summary>
        /// Determines whether [is whole word] [the specified text].
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="word">The word.</param>
        /// <param name="wordStartIndex">Start index of the word.</param>
        /// <returns>
        ///   <c>true</c> if [is whole word] [the specified text]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsWholeWord(this string text, string word, int wordStartIndex = 0)
        {
            var previewWholeChar = string.Empty;
            var followWholeChar = string.Empty;

            if (wordStartIndex > 0 && text.Length > 0)
            {
                previewWholeChar = text.Substring(wordStartIndex - 1, 1);
            }

            if (text.Length > 0 && text.Length > wordStartIndex + word.Length + 1)
            {
                followWholeChar = text.Substring(wordStartIndex + word.Length, 1);
            }

            var test = previewWholeChar + word + followWholeChar;
            return test.Trim() == word && word.Split().Length == 1;
        }
    }
}
